from . import passport_blue
from flask import request, abort, make_response, jsonify, session
from info.utils.captcha.captcha import captcha
from info import redis_store, constants, response_code, db
import logging, re, random, datetime
from info.libs.yuntongxun.sms import CCP
from info.models import User



@passport_blue.route('/image_code',methods=['GET'])
def get_image_cold():
    """提供图片的验证码，下面是我的思路。。。
    1，发送请求获取图片的验证码
    2，接受请求，检验参数。
    3，生产图片的验证码
    4，经用户的uuid与生产的验证码绑定在一起
    5，将用户的验证码 以及uuid存入redis中
    6，反回用户验证码
    """
    # 1，发送请求获取图片的验证码，获取接受当前的图片编号id
    # 从redis 中获取imageCodeId，并定义为image_code_id
    image_code_id = request.args.get('imageCodeId')
    # 2,接受参数，检验参数，主要是检测是否为空
    if not image_code_id:
        abort(400) #缺少参数
    # 3.生成图片验证码的文字和图片信息:text是图片验证码的文字；image是图片验证码图片
    # 注意点： 需要在虚拟环境中安装Pillow模块
    # generate_captcha函数返回值为name，text，image，不信去看源代码
    name, text, image = captcha.generate_captcha()
    # 4,将用户的uuid与验证码绑定在一起，并且存入redis中
    # 后方的constants.IMAGE_CODE_REDIS_EXPIRES是我们定义的时间文档，300秒
    # 因为项目中可能有很多要用到时间，如果修改的话我们也不可能一个一个修改，所以统一
    # 定义在一个文档中，统一修改
    try:
        # "ImageCode" + image_code_id:拼接方式，这样的话就会在redis显示（ImageCode7fb448c4-bc1d-4565-8e47-d9ee5489f358）
        redis_store.set("ImageCode" + image_code_id, text, constants.IMAGE_CODE_REDIS_EXPIRES)
    except Exception as e:
        logging.error(e)
        abort(500) # 表示服務器錯誤的
    # 5，返回用戶验证码
    # 将image作为响应体
    # make_reponse:制作响应
    response = make_response(image)
    # 指定响应的数据类型
    # Content-Type:可以指定响应的数据类型，但是它是在响应头中
    response.headers['Content-Type'] = 'image/jpg'
    return response


@passport_blue.route('/sms_code',methods=['POST'])
def send_sms_code():
    """
    自己分析的步骤：
    1，服务器向容联云发送获取短信验证码的请求
    2，验证用户的手机号码
    3，根据用户的uuid与验证码与我们redis库中储存的数据进行匹配
    4，如果匹配的 数据正确则生成短信，不然报错
    5，发送短信给用户，并将短信验证码保存到redis数据库中
    """
    """
    老师的步骤
    1.接受参数：mobile, image_code, image_code_id
    2.校验参数：判断参数是否齐全，判断手机号格式是否正确
    3.使用image_code_id从redis中读取出服务器存储的图片验证码
    4.使用用户输入的图片验证码 对比 服务器存储的图片验证码
    5.如果对比成功生成短信验证码，长度是6位的随机数字
    6.再使用CCP()单例发送短信验证码
    7.发送短信验证码成功，就把短信验证码存储到redis()
    8.返回短信验证码发送的结果
    """
    # 1.接受参数：mobile, image_code, image_code_id
    # 直接接受json数据，一定要和前段说好了，让她直接发送json数据
    json_dict = request.json
    # 把我们接受到的数据放到redis中，分别是mobile：电话号码。image_code_client:验证码
    # image_code_id:生成的uuid
    mobile = json_dict.get('mobile')
    image_code_client = json_dict.get('image_code')
    image_code_id = json_dict.get('image_code_id')
    # 2.校验参数：判断参数是否齐全，判断手机号格式是否正确
    if not all([mobile,image_code_client,image_code_id]):
        # 因为参数不完整，直接返回错误，后面的RET.PARAMERRY详细请见response_code.py文件
        return jsonify(errno=response_code.RET.PARAMERR,errmsg="缺少参数")
    #     正则匹配手机号码，判断是否正确
    if not re.match('^1[345678][0-9]{9}$', mobile):
        return jsonify(errno=response_code.RET.PARAMERR,errmsg='电话格式错误')
    # 3，使用image_code_id从redis中读取出服务器储存的图片验证码
    try:
        # redis_store就相当于redis中的内容,这句话可以理解为image_code_server就相当于
        # 从redis中获得image_code_id,并且以拼接字符串的方式在前方拼接上"ImageCode"
        image_code_server = redis_store.get("ImageCode" + image_code_id)
    except Exception as e:
        logging.error(e)
        return jsonify(errno=response_code.RET.NODATA,errmsg="查询图片验证码失败")
    # 验证码是有时间限制 的，首先判断验证吗是否还存在
    if not image_code_server:
        return jsonify(errno=response_code.RET.NODATA,errmsg="图片验证码不存在")
    # 4，使用用户输入的验证码对比服务器储存的验证码：
    # 再把两个验证码进行比对
    if image_code_client.upper() != image_code_server.upper():
        return jsonify(errno=response_code.RET.PARAMERR,errmsg="验证码输入有误")
    # 5，如果对比成功验证吗，则生成随机的6位数验证码
    # 前面的意思是：如果生成的数字不足6位，则前面使用0来填充
    sms_code = '%06d' % random.randint(0, 999999)
    logging.debug(sms_code)
    # 6,使用CCP单例发送短信
    # 意思是，想mobile发送短信，验证码为sms_code，有效期为5分钟，使用的模板为1号
    result = CCP().send_sms_code(mobile, [sms_code, constants.SMS_CODE_REDIS_EXPIRES / 5], "1")
    if result != 0:
        return jsonify(errno=response_code.RET.THIRDERR,errmsg="没话费了啊")
    # 7，发送验证吗成功，就把我们发送给的验证码保存到redis中，方便以后登陆使用
    try:
        # 后面面的是短信验证码有效时间300秒
        redis_store.set('SMS:' + mobile,sms_code,constants.SMS_CODE_REDIS_EXPIRES)
    except Exception as e:
        logging.error(e)
        return jsonify(errno=response_code.RET.DATAERR,errmsg="短信储存失败")
    # 8，返回短信验证码的发送结果
    return jsonify(errno=response_code.RET.OK,errmsg="短信发送成功")

# 设置注册接口的函数
@passport_blue.route('/register', methods=['POST'])
def register():
    """
    我的思路分析：
    1，接受前端参数，mobile，smscode,password
    2,效验接受到的参数，手机号格式正不正确，密码格式正不正确
    3，将接收到的验证码与我们数据库中的验证码进行比较，看看是否相同
    4，注册成功，并且记录当前的登陆时间，保持当前的状态(因为注册成功即登陆成功)
    5，返回成功的信息
    :return:
    """
    """
    老师的思路：
     1.接受参数：mobile, smscode, password(明文)
    2.校验参数：参数是否齐全，校验手机号码格式是否正确
    3.使用mobile读取redis中短信验证码
    4.使用客户端传入的短信验证码和服务器短信验证码进行对比
    5.创建User模型对象,并给用户属性赋值
    6.记得保存最后一次登录的时间（last_login,为了实现注册即登录）
    7.需要将用户注册数据保存到mysql数据库
    8.将状态保持信息写入到session(为了实现注册即登录)
    9.返回注册结果
    """
    # 1.接受参数：mobile, smscode, password(明文)
    json_dict = request.json
    mobile = json_dict.get('mobile')
    sms_code_client = json_dict.get('smscode')
    password = json_dict.get('password')
    # 2.校验参数：参数是否齐全，校验手机号码格式是否正确
    if not all([mobile,sms_code_client,password]):
        return jsonify(errno=response_code.RET.PARAMERR,errmsg="您输入的信息不完整 ")
    if not re.match('^1[345678][0-9]{9}$', mobile):
        return jsonify(errno=response_code.RET.PARAMERR,errmsg='电话格式错误')
    #  3.使用mobile读取redis中短信验证码
    try:
        sms_code_server = redis_store.get('SMS:' + mobile)
    except Exception as e:
        logging.error(e)
        return jsonify(errno=response_code.RET.NODATA, errmsg="验证码输入有误")
    if not sms_code_server:
        return jsonify(errno=response_code.RET.NODATA, errmsg="验证码过期")

    # 4.使用客户端传入的短信验证码和服务器短信验证码进行对比
    if sms_code_server != sms_code_client:
        return jsonify(errno=response_code.RET.PARAMERR, errmsg="验证码输入有误")
    # 5.创建User模型对象,并给用户属性赋值
    user = User()
    user.nick_name = mobile
    user.mobile = mobile

    # password 是明文，而password_hash需要存储密文
    # password : 是我即将给User模型类增加的属性（python是面向对象的高级编程语言，可以在代码运行的过程中给对象添加属性）
    # 再在password属性的setter方法中，拿着明文密码进行加密处理，再保存到password_hash
    user.password = password
    # 6.记得保存最后一次登录的时间（last_login, 为了实现注册即登录）
    user_last_login = datetime.datetime.now()

    # 7.需要将用户注册数据保存到mysql数据库
    try:
        db.session.add(user)
        db.session.commit()
    except Exception as e:
        logging.error(e)
        db.session.rollback()
        return jsonify(errno=response_code.RET.DATAERR, errmsg="文件保存错误")
    # 8.将状态保持信息写入到session(为了实现注册即登录)
    session['user_id'] = user.id
    session['nick_name'] = user.nick_name
    session['mobile'] = user.mobile
    # 9.返回注册结果
    return jsonify(errno=response_code.RET.OK, errmsg="注册成功")

# 用户登陆功能
@passport_blue.route('/login', methods=['POST'])
def login():
    """
    我的分析：
    1，接受用户传来的参数，mobile，password
    2，校检用户传入的参数，不能为空，手机号合法
    3，如果都合法的话，查找用户mobile在redis中的数据
    4，如果在redis中有数据的话，那么就调出来和用户输入的password进行比对
    5，如果都正确，显示登陆成功，记录登陆时
    ，状态保持
    6，返回登录信息
    :return:
    """
    """
    老师的分析：
    1.接受参数：mobile, password(明文)
    2.校验参数：参数是否齐全，校验手机号码格式是否正确
    3.使用mobile查询user是否存在
    4.如果user存在，再去校验密码
    5.如果密码校验通过，就记录最后一次登录的时间和状态保持
    6.响应登录结果
    """
    # 1.接受参数：mobile, password(明文)
    json_dict = request.json
    mobile = json_dict.get('mobile')
    password = json_dict.get('password')

    # 2.校验参数：参数是否齐全，校验手机号码格式是否正确
    if not all([mobile,password]):
        return jsonify(errno=response_code.RET.PARAMERR, errmsg="参数错误")
    if not re.match('^1[345678][0-9]{9}$', mobile):
        return jsonify(errno=response_code.RET.PARAMERR,errmsg='电话格式错误')

    # 3.使用mobile查询user是否存在
    try:
        user = User.query.filter(User.mobile == mobile).first()
    except Exception as e:
        logging.error(e)
        return jsonify(errno=response_code.RET.DBERR, errmsg='账号密码错误')
    if not user:
        return jsonify(errno=response_code.RET.DBERR, errmsg='账号密码错误')

    # 4.如果user存在，再去校验密码,因为我们在后台的密码是加密的，所以只能用check_password
    # 来比对
    if not user.check_password:
        return jsonify(errno=response_code.RET.DBERR, errmsg='账号密码错误')

    # 5.如果密码校验通过，就记录最后一次登录的时间和状态保持
    user_last_time = datetime.datetime.now()
    # 状态保持
    session['mobile'] = user.mobile
    session['nick_name'] = user.mobile
    session['user_id'] = user.id

    # 6.响应登录结果
    return jsonify(errno=response_code.RET.OK, errmsg='登陆成功')

# 删除功能
@passport_blue.route('/logout', methods=['GET'])
def logout():
    """
    自己的分析：
    1，把所有状态保持的东西都删了
    2，返回删除成功的信息
    :return:
    """
    # 1，把所有状态保持的东西都删了
    session.pop('user_id', None)
    session.pop('nick_name', None)
    session.pop('mobile', None)

    # 2.返回退出登录的结果
    return jsonify(errno=response_code.RET.OK, errmsg='退出登录成功')